/**
  ******************************************************************************
  * @file           : studio_udp.cpp
  * @author         : wangyingjie
  * @brief          : None
  * @attention      : None
  * @date           : 2025/7/2
  ******************************************************************************
  */

#include "studio_udp.h"


studio_udp::studio_udp(
    const std::string& local_ip,
    unsigned short local_port,
    const std::string& remote_ip,
    unsigned short remote_port,
    size_t buffer_size)
    : socket_(io_context_),
      remote_endpoint_(asio::ip::make_address(remote_ip), remote_port),
      buffer_size_(buffer_size),
      running_(false)

{
    asio::ip::udp::endpoint local_endpoint(asio::ip::make_address(local_ip), local_port);
    boost::system::error_code ec;
    socket_.open(local_endpoint.protocol(), ec);
    if (ec)
    {
        std::cerr << "[Error] Failed to open UDP socket: " << ec.message() << std::endl;
        return;
    }

    socket_.bind(local_endpoint, ec);
    if (ec)
    {
        std::cerr << "[Error] Failed to bind UDP socket: " << ec.message() << std::endl;
        return;
    }
}

studio_udp::~studio_udp()
{
    stop();
    if (io_thread_.joinable())
    {
        io_thread_.join();
    }
}

bool studio_udp::start()
{
    if (running_)
        return false;

    running_ = true;

    // IO线程运行
    io_thread_ = std::thread([this]() {
        do_receive(); // 开始异步接收
        io_context_.run();
    });

    return true;
}

void studio_udp::stop()
{
    if (!running_)
        return;

    running_ = false;

    io_context_.stop(); // 停止io_context循环
}

void studio_udp::send(const std::string& message)
{
    if (!socket_.is_open())
        return;

    socket_.async_send_to(
        asio::buffer(message),
        remote_endpoint_,
        [](const boost::system::error_code&, std::size_t) {
        }
        );
}

void studio_udp::set_receive_callback(receive_callback callback)
{
    recv_callback_ = callback;
}

void studio_udp::do_receive()
{
    std::shared_ptr<std::vector<char>> buffer = std::make_shared<std::vector<char>>(buffer_size_);

    socket_.async_receive_from(
        asio::buffer(*buffer),
        remote_endpoint_,
        [this, buffer](const boost::system::error_code& error, std::size_t bytes_recvd) {
            if (!error && recv_callback_)
            {
                std::string received_data(buffer->data(), bytes_recvd);
                recv_callback_(received_data, remote_endpoint_);
            }

            // 继续下一次接收
            do_receive();
        }
        );
}